#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Petri网图形元素模块
定义Petri网中的各种图形元素（位置、转换、弧等）
"""

from PyQt5.QtWidgets import (QGraphicsItem, QGraphicsEllipseItem,
                            QGraphicsRectItem, QGraphicsPathItem,
                            QGraphicsTextItem, QGraphicsItemGroup)
from PyQt5.QtCore import Qt, QRectF, QPointF
from PyQt5.QtGui import QPen, QBrush, QColor, QPainterPath, QFont

class PlaceItem(QGraphicsEllipseItem):
    """位置节点类"""
    
    def __init__(self, name, x, y, radius=20):
        """初始化位置节点
        
        Args:
            name: 节点名称
            x: x坐标
            y: y坐标
            radius: 圆形半径
        """
        super().__init__(-radius, -radius, 2*radius, 2*radius)
        self.setPos(x, y)
        self.name = name
        self.radius = radius
        self.tokens = 0
        
        # 设置样式
        self.setPen(QPen(QColor("#2c3e50"), 2))
        self.setBrush(QBrush(Qt.white))
        
        # 添加名称标签
        self.label = QGraphicsTextItem(name, self)
        self.label.setDefaultTextColor(QColor("#2c3e50"))
        self.label.setFont(QFont("Arial", 10))
        label_width = self.label.boundingRect().width()
        self.label.setPos(-label_width/2, radius + 5)
        
        # 设置交互标志
        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable)
    
    def set_tokens(self, count):
        """设置标记数量
        
        Args:
            count: 标记数量
        """
        self.tokens = count
        self.update()
    
    def paint(self, painter, option, widget):
        """绘制位置节点
        
        Args:
            painter: QPainter对象
            option: 样式选项
            widget: 父部件
        """
        # 绘制圆形
        super().paint(painter, option, widget)
        
        # 如果被选中，绘制高亮效果
        if self.isSelected():
            painter.setPen(QPen(QColor("#3498db"), 3))
            painter.drawEllipse(self.boundingRect())
        
        # 绘制标记
        if self.tokens > 0:
            token_radius = 4
            if self.tokens == 1:
                # 单个标记居中显示
                painter.setBrush(QBrush(QColor("#2c3e50")))
                painter.setPen(Qt.NoPen)
                painter.drawEllipse(QPointF(0, 0), token_radius, token_radius)
            else:
                # 多个标记环形排列
                angle_step = 360.0 / min(self.tokens, 8)
                token_distance = self.radius * 0.5
                for i in range(min(self.tokens, 8)):
                    angle = i * angle_step
                    x = token_distance * math.cos(math.radians(angle))
                    y = token_distance * math.sin(math.radians(angle))
                    painter.setBrush(QBrush(QColor("#2c3e50")))
                    painter.setPen(Qt.NoPen)
                    painter.drawEllipse(QPointF(x, y), token_radius, token_radius)
                
                # 如果标记数超过8，显示数字
                if self.tokens > 8:
                    painter.setPen(QPen(QColor("#2c3e50")))
                    painter.setFont(QFont("Arial", 8))
                    painter.drawText(QRectF(-10, -10, 20, 20),
                                   Qt.AlignCenter,
                                   str(self.tokens))
    
    def hoverEnterEvent(self, event):
        """鼠标悬停进入事件"""
        self.setPen(QPen(QColor("#3498db"), 2))
        super().hoverEnterEvent(event)
    
    def hoverLeaveEvent(self, event):
        """鼠标悬停离开事件"""
        self.setPen(QPen(QColor("#2c3e50"), 2))
        super().hoverLeaveEvent(event)

class TransitionItem(QGraphicsRectItem):
    """转换节点类"""
    
    def __init__(self, name, x, y, width=30, height=40):
        """初始化转换节点
        
        Args:
            name: 节点名称
            x: x坐标
            y: y坐标
            width: 矩形宽度
            height: 矩形高度
        """
        super().__init__(-width/2, -height/2, width, height)
        self.setPos(x, y)
        self.name = name
        
        # 设置样式
        self.setPen(QPen(QColor("#2c3e50"), 2))
        self.setBrush(QBrush(QColor("#ecf0f1")))
        
        # 添加名称标签
        self.label = QGraphicsTextItem(name, self)
        self.label.setDefaultTextColor(QColor("#2c3e50"))
        self.label.setFont(QFont("Arial", 10))
        label_width = self.label.boundingRect().width()
        self.label.setPos(-label_width/2, height/2 + 5)
        
        # 设置交互标志
        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable)
    
    def paint(self, painter, option, widget):
        """绘制转换节点
        
        Args:
            painter: QPainter对象
            option: 样式选项
            widget: 父部件
        """
        # 绘制矩形
        super().paint(painter, option, widget)
        
        # 如果被选中，绘制高亮效果
        if self.isSelected():
            painter.setPen(QPen(QColor("#3498db"), 3))
            painter.drawRect(self.boundingRect())
    
    def hoverEnterEvent(self, event):
        """鼠标悬停进入事件"""
        self.setPen(QPen(QColor("#3498db"), 2))
        super().hoverEnterEvent(event)
    
    def hoverLeaveEvent(self, event):
        """鼠标悬停离开事件"""
        self.setPen(QPen(QColor("#2c3e50"), 2))
        super().hoverLeaveEvent(event)

class ArcItem(QGraphicsPathItem):
    """弧类"""
    
    def __init__(self, start_item, end_item, weight=1):
        """初始化弧
        
        Args:
            start_item: 起始节点
            end_item: 终止节点
            weight: 弧的权重
        """
        super().__init__()
        self.start_item = start_item
        self.end_item = end_item
        self.weight = weight
        
        # 设置样式
        self.setPen(QPen(QColor("#2c3e50"), 2))
        
        # 创建箭头路径
        self.arrow_size = 10
        self.update_path()
        
        # 添加权重标签
        if weight > 1:
            self.weight_label = QGraphicsTextItem(str(weight), self)
            self.weight_label.setDefaultTextColor(QColor("#2c3e50"))
            self.weight_label.setFont(QFont("Arial", 10))
            self.update_weight_label()
        
        # 设置交互标志
        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable)
    
    def update_path(self):
        """更新弧的路径"""
        # 计算起点和终点
        start_pos = self.start_item.scenePos()
        end_pos = self.end_item.scenePos()
        
        # 创建路径
        path = QPainterPath()
        path.moveTo(start_pos)
        
        # 如果是自环，创建圆形路径
        if self.start_item == self.end_item:
            radius = 30
            center = start_pos + QPointF(radius, -radius)
            path.arcTo(center.x()-radius, center.y()-radius,
                      2*radius, 2*radius, 0, 360)
        else:
            # 创建直线路径
            path.lineTo(end_pos)
        
        # 添加箭头
        angle = math.atan2(end_pos.y()-start_pos.y(),
                          end_pos.x()-start_pos.x())
        arrow_p1 = end_pos - QPointF(math.cos(angle + math.pi/6) * self.arrow_size,
                                   math.sin(angle + math.pi/6) * self.arrow_size)
        arrow_p2 = end_pos - QPointF(math.cos(angle - math.pi/6) * self.arrow_size,
                                   math.sin(angle - math.pi/6) * self.arrow_size)
        path.lineTo(arrow_p1)
        path.moveTo(end_pos)
        path.lineTo(arrow_p2)
        
        self.setPath(path)
    
    def update_weight_label(self):
        """更新权重标签位置"""
        if self.weight > 1:
            path = self.path()
            point = path.pointAtPercent(0.5)
            self.weight_label.setPos(point)
    
    def paint(self, painter, option, widget):
        """绘制弧
        
        Args:
            painter: QPainter对象
            option: 样式选项
            widget: 父部件
        """
        # 如果被选中，绘制高亮效果
        if self.isSelected():
            painter.setPen(QPen(QColor("#3498db"), 3))
        else:
            painter.setPen(self.pen())
        
        painter.drawPath(self.path())
    
    def hoverEnterEvent(self, event):
        """鼠标悬停进入事件"""
        self.setPen(QPen(QColor("#3498db"), 2))
        super().hoverEnterEvent(event)
    
    def hoverLeaveEvent(self, event):
        """鼠标悬停离开事件"""
        self.setPen(QPen(QColor("#2c3e50"), 2))
        super().hoverLeaveEvent(event)

class TokenAnimation:
    """标记动画类"""
    
    def __init__(self, scene, start_place, end_place, duration=1000):
        """初始化标记动画
        
        Args:
            scene: 场景对象
            start_place: 起始位置
            end_place: 终止位置
            duration: 动画持续时间（毫秒）
        """
        self.scene = scene
        self.start_place = start_place
        self.end_place = end_place
        self.duration = duration
        
        # 创建动画标记
        self.token = QGraphicsEllipseItem(-4, -4, 8, 8)
        self.token.setBrush(QBrush(QColor("#2c3e50")))
        self.token.setPen(Qt.NoPen)
        
        # 设置初始位置
        self.token.setPos(start_place.scenePos())
        
        # 添加到场景
        self.scene.addItem(self.token)
        
        # 创建动画定时器
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_position)
        self.progress = 0
        self.step = 1000 / duration  # 每毫秒的进度增量
    
    def start(self):
        """开始动画"""
        self.timer.start(16)  # 约60fps
    
    def update_position(self):
        """更新标记位置"""
        self.progress += self.step
        if self.progress >= 100:
            # 动画结束
            self.timer.stop()
            self.scene.removeItem(self.token)
            return
        
        # 计算当前位置
        start_pos = self.start_place.scenePos()
        end_pos = self.end_place.scenePos()
        current_pos = QPointF(
            start_pos.x() + (end_pos.x() - start_pos.x()) * self.progress / 100,
            start_pos.y() + (end_pos.y() - start_pos.y()) * self.progress / 100
        )
        self.token.setPos(current_pos) 